package org.twndmv.ejb;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.annotation.security.RolesAllowed;
import javax.ejb.EJBException;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Session;
import javax.jms.Topic;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.twndmv.bl.DriverMgmt;
import org.twndmv.blimpl.DriverMgmtImpl;
import org.twndmv.bo.Person;
import org.twndmv.bo.Residence;
import org.twndmv.dao.PersonDAO;
import org.twndmv.dto.DTOUtils;
import org.twndmv.dto.PersonDTO;
import org.twndmv.dto.ResidenceDTO;
import org.twndmv.jpa.PersonDAOImpl;

@Stateless
@RolesAllowed({ "dmv-federated","dmv-tactical","dmv-admin" })
public class DriverMgmtEJB implements DriverMgmtRemote {

	private static Log log = LogFactory.getLog(DriverMgmtEJB.class);

	@Resource(mappedName = "java:/JmsXA")
	private ConnectionFactory connFactory;
	@Resource(mappedName = "java:/topic/ejava/projects/datashare/dmv", type = Topic.class)
	private Destination dmvTopic;

	private DMVPublisher dmvPublisher;

	@PersistenceContext(unitName = "dmvEntity")
	private EntityManager em;

	private DriverMgmt driverManager;

	@PostConstruct
	public void init() {
		try {
			log.info("**** init ****");
			log.info("em=" + em);
			PersonDAO personDB = new PersonDAOImpl(em);
			driverManager = new DriverMgmtImpl(personDB);
			dmvPublisher = new DMVPublisher("DMVPublisherEJB");
		} catch (Throwable ex) {
			log.error("error in init", ex);
			throw new EJBException("error in init" + ex);
		}
	}

	@Override
	@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
	@RolesAllowed({ "dmv-tactical","dmv-admin" })
	public void addDriver(PersonDTO newPerson) {
		Person newPeep = DTOUtils.convertDTOToPerson(newPerson);
		driverManager.addDriver(newPeep);
		Connection connection = null;
		Session session = null;
		try {
			 connection = connFactory.createConnection();
			 session = connection.createSession(false,
					Session.AUTO_ACKNOWLEDGE);
			dmvPublisher.publishDMVChange(session, dmvTopic, newPeep.getFirstName(),
					newPeep.getMiddleName(), newPeep.getLastName());
		} catch (Exception e) {
			log.error("Error publishing DMV Person change: " + e);
		}
		finally {
			if (connection != null) {
				try {
					connection.close();
				} catch (JMSException e) {
					log.error("Error closing connection: " + e);
				}
			}
			if (session != null) {
				try {
					session.close();
				} catch (JMSException e) {
					log.error("Error closing connection: " + e);
				}
			}
		}
	}

	@Override
	@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
	@RolesAllowed({ "dmv-tactical","dmv-admin" })
	public void moveResidence(long personId, ResidenceDTO newResidence) {

		Residence newRes = DTOUtils.convertDTOToResidence(newResidence);
		driverManager.moveResidence(personId, newRes);
		Person newPeep = driverManager.getDriver(personId);

		try {
			Connection connection = connFactory.createConnection();
			Session session = connection.createSession(false,
					Session.AUTO_ACKNOWLEDGE);
			dmvPublisher.publishDMVChange(session, dmvTopic, newPeep.getFirstName(),
					newPeep.getMiddleName(), newPeep.getLastName());
		} catch (Exception e) {
			log.error("Error publishing DMV Person change: " + e);
		}

	}

	@Override
	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public PersonDTO getDriver(long id) {
		Person newPeep = driverManager.getDriver(id);
		return DTOUtils.convertPersonToDTO(newPeep);
	}

	@Override
	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public List<PersonDTO> getDriversByLastName(String name) {
		List<PersonDTO> results = new ArrayList<PersonDTO>();
		for (Person p : driverManager.getDriversByLastName(name)) {
			PersonDTO person = DTOUtils.convertPersonToDTO(p);
			results.add(person);
		}
		return results;
	}

	@Override
	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public List<PersonDTO> getAllDrivers() {
		List<PersonDTO> results = new ArrayList<PersonDTO>();
		for (Person p : driverManager.getAllDrivers()) {
			PersonDTO person = DTOUtils.convertPersonToDTO(p);
			results.add(person);
		}
		return results;
	}

}
